package io.gitee.caoxiaoyu97.log4j.defender.message.log;

import io.gitee.caoxiaoyu97.log4j.defender.constants.DefenderConstants;
import io.gitee.caoxiaoyu97.log4j.defender.properties.DefenderKeyProperties;
import io.gitee.caoxiaoyu97.log4j.defender.replacer.ReplaceStrategy;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

public abstract class AbstractLogDefender<Matcher> {
    private static final Logger logger = LoggerFactory.getLogger(AbstractLogDefender.class);
    protected Set<Matcher> toMatchKeys;
    protected ReplaceStrategy strategy;
    protected boolean isEffective;

    public AbstractLogDefender(DefenderKeyProperties properties) {
        if (null == properties) {
            return;
        }
        try {
            this.toMatchKeys = transformToMatcher(properties);
        } catch (Exception e) {
            logger.warn("Failed to resolve match. {}", e.getMessage());
        }
        this.strategy = new ReplaceStrategy(properties.getRemainprefix(), properties.getRemainsuffix(), properties.getMarkchar());
        this.isEffective = (!CollectionUtils.isEmpty(this.toMatchKeys) && null != this.strategy);
    }

    protected Set<String> readKeysFromProperty(String keys, String splitter) {
        Set<String> keySet = new HashSet<>();
        if (!StringUtils.isEmpty(keys)) {
            keySet.addAll(Arrays.asList(getSplitPattern(splitter).split(keys)));
        }
        return keySet;
    }


    protected Pattern getSplitPattern(String splitter) {
        try {
            StringBuilder splitPattern = (new StringBuilder("\\s*[")).append(splitter).append("]+\\s*");
            return Pattern.compile(splitPattern.toString());
        } catch (Exception e) {
            return DefenderConstants.DEFAULT_SPLIT_PATTERN;
        }
    }

    protected abstract Set<Matcher> transformToMatcher(DefenderKeyProperties paramDefenderKeyProperties);

    public StringBuilder desensitize(StringBuilder input) {
        try {
            return this.isEffective ? (isQuickMatch(input) ? doDesensitize(input) : input) : input;
        } catch (Throwable e) {
            logger.debug(e.getMessage(), e);

            return input;
        }
    }

    protected abstract StringBuilder doDesensitize(StringBuilder paramStringBuilder);

    protected abstract boolean isQuickMatch(StringBuilder paramStringBuilder);
}
